package service

import (
	"context"

	"go.uber.org/multierr"

	messagev1 "gitee.com/flycash/simple-im/api/proto/gen/message/v1"
	"gitee.com/flycash/simple-im/internal/domain"
	"gitee.com/flycash/simple-im/internal/event/msg"
	"gitee.com/flycash/simple-im/internal/repository"
	msgv1 "gitee.com/flycash/ws-gateway/api/proto/gen/gatewayapi/v1"
	"google.golang.org/protobuf/encoding/protojson"
)

type MessageService interface {
	// Send 消息的生产
	Send(ctx context.Context, msg domain.Message) (int64, error)
	// 获取历史消息
	HistoryMessages(ctx context.Context, cid, lastMsgID int64, offset, limit int) ([]domain.Message, error)
}

type messageService struct {
	repo     repository.MessageRepository
	producer msg.Producer
	chanRepo repository.ChannelRepository
}

func NewMessageService(repo repository.MessageRepository,
	chanRepo repository.ChannelRepository,
	producer msg.Producer,
) MessageService {
	return &messageService{
		repo:     repo,
		producer: producer,
		chanRepo: chanRepo,
	}
}

func (m *messageService) HistoryMessages(ctx context.Context, cid, lastMsgID int64, offset, limit int) ([]domain.Message, error) {
	return m.repo.GetHistoryMessages(ctx, cid, lastMsgID, offset, limit)
}

func (m *messageService) Send(ctx context.Context, message domain.Message) (int64, error) {
	id, err := m.repo.SaveMessage(ctx, message)
	if err != nil {
		return 0, err
	}
	immsg := &messagev1.ImMessage{
		Id:          id,
		Content:     message.Content,
		Key:         message.Key,
		ContentType: message.ContentType,
		Cid:         message.Cid,
		Sender:      message.Sender,
		SendTime:    message.SendTime,
	}
	body, err := protojson.Marshal(immsg)
	if err != nil {
		return 0, err
	}
	// 从 Channel 里面找到所有的用户，排除掉自己
	receivers, err := m.chanRepo.FindChannelMembersByCID(ctx, message.Cid)
	if err != nil {
		return 0, err
	}

	for _, r := range receivers {
		if r.ID == message.Sender {
			continue
		}
		err = multierr.Append(err, m.producer.Produce(ctx, &msgv1.PushMessage{
			Key:        message.Key,
			BizId:      1,
			ReceiverId: r.ID,
			Body:       body,
		}))
	}
	return id, err
}
